﻿/// <reference path="_namespace.js" />
/// <reference path="../IGetEvent.js" />
/// <reference path="../IHaveDocument.js" />
/// <reference path="../events/EventRouter.js" />
/// <reference path="ArrayListEventArgs.js"/>
/// <reference path="IComparer.js" />
/// <reference path="../IComparable.js" />
/// <reference path="../DomElements.js" />

/*****************************************************************************
MS Ajax library class definition. Inheriting from ajax.BaseObject.
Author: krobinson 10/7/2008 11:53:50 AM.
Class:  ajax.collections.ArrayList
*****************************************************************************/

$addNamespace("ajax.collections");
$imports("ajax.collections.ArrayListEventArgs");
//-----------------------------------------------------------------------------

ajax.collections.ArrayList = function(doc)
{///<summary>Use this class instead of Array when you want to use array events.</summary>
    ajax.collections.ArrayList.superConstructor.apply(this, arguments);
    this._doc = doc;
    this._window = ajax.lang.getDocumentWindow(doc);
    this._lastIndex = -1; 
    // Events
    this.getEvent(this.getWindow(), "onAdded");
    this.getEvent(this.getWindow(), "onRemoved");  
}
ajax.lang.extend("ajax.collections.ArrayList", "ajax.BaseObject");
ajax.lang.supports("ajax.collections.ArrayList", "ajax.IHaveDocument");

if ($getDesignMode())
    ajax.collections.ArrayList.prototype = ajax.BaseObject.prototype;
//-----------------------------------------------------------------------------

ajax.collections.ArrayList.prototype._doc = null;
ajax.collections.ArrayList.prototype._window = null;

// Public members
//-----------------------------------------------------------------------------
// IGetEvent implementation
ajax.collections.ArrayList.prototype.getEvent = function(wind, eventType)
{///<summary>Returns the existing or new event router (delegate) for the event name.</summary>
    ///<returns type="ajax.events.EventRouter"></returns>
    ///<param name="wind" type="DomWindow">A window handle</param>
    ///<param name="eventType" type="String">The string name of the event</param>
    var router = $call("ajax.events.EventRouter", "getEvent", wind, this, eventType);
    return router;
}

//-----------------------------------------------------------------------------
// IHaveDocument implementation
ajax.collections.ArrayList.prototype.getDocument = function() 
{///<returns type="domDocument"/> 
    return this._doc; 
}
ajax.collections.ArrayList.prototype.getWindow   = function() 
{///<returns type="domWindow"/>
    return this._window; 
}

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype._lastIndex = -1;



// Public Methods
//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.add_added = function(handler){ this.getEvent(this.getWindow(), "onAdded").addListener(handler); };
ajax.collections.ArrayList.prototype.remove_added = function(handler) { this.getEvent(this.getWindow(), "onAdded").removeListener(handler); };
ajax.collections.ArrayList.prototype.add_removed = function(handler) { this.getEvent(this.getWindow(), "onRemoved").addListener(handler); };
ajax.collections.ArrayList.prototype.remove_removed = function(handler) { this.getEvent(this.getWindow(), "onRemoved").removeListener(handler); };

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.get_count = function() 
{///<summary>Returns the number of elements in the array.</summary>
    return this._lastIndex + 1; 
}


//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.indexOf = function(obj)
{///<summary>Returns the first index position of the object passed in the array. -1 if not found.</summary>
    for (var i = 0; i < this.get_count(); i++)
        if (this[i] === obj)
            return i;
    return -1;
}

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.contains = function(obj)
{///<summary>Returns true if the object passed is found in the array.</summary>
    return (this.indexOf(obj) >= 0);
}

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.sort = function(comparer)
{///<summary>Sorts the elements in the entire System.Collections.ArrayList using the specified comparer.</summary>
 ///<param name="comparer" type="ajax.collections.IComparer">
 /// The ajax.collections.IComparer implementation to use when comparing elements.
 /// -or- null to use the System.IComparable implementation of each element.
 ///</param>
    
    if (this._lastIndex < 1)
        return;            
        
    // Just do a simple bubble sort...
    var temp = null;
    var keepChecking = true;
    while (keepChecking)
    {    
        keepChecking = false;
        for (var i = 0; i < this._lastIndex; i++)
        {            
            if (comparer)
            {
                // Use Comparer 
                comparer = ajax.collections.IComparer.cast(comparer);                
                if (comparer.compare(this[i], this[i + 1]) > 0) // wrong way round
                {
                    keepChecking = true;
                    temp = this[i + 1];
                    this[i + 1] = this[i];
                    this[i] = temp;
                }
            }           
            else
            {            
                // Use IComparable implementation of each element 
                if (ajax.IComparable.cast(this[i]).compareTo(this[i + 1]) > 0) // wrong way round
                {
                    keepChecking = true;
                    temp = this[i + 1];
                    this[i + 1] = this[i];
                    this[i] = temp;
                }
            }                                  
        }
    }    
}


//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.add = function(obj, noDuplicates)
{///<returns>The index position of the added item.</returns>
 ///<param name="obj" type="Object">The object to add.</param>
 ///<param name="noDuplicated" type="boolean">Optional. Pass true to ignore duplicate values. Defaults false.</param>
 
    noDuplicates = (typeof (noDuplicates) == "undefined") ? false : true;
 
    if (noDuplicates && this.contains(obj)) // check
        return -1;
        
    this[++this._lastIndex] = obj; // add
        
    // fire event
    var args = new ajax.collections.ArrayListEventArgs(null, this, obj, this._lastIndex);    
    this.onAdded.call(this, args);
    return this._lastIndex;
}

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.addAt = function(index, obj, noDuplicates)
{///<returns>The index position of the added item.</returns>
 ///<param name="index" type="number" integer="true">The zero based index at which the value should be added.</param>
 ///<param name="obj" type="Object">The object to add.</param>
 ///<param name="noDuplicated" type="boolean">Optional. Pass true to ignore duplicate values. Defaults false.</param>
    
    noDuplicates = (typeof(noDuplicates) == "undefined") ? false : true;
    
    if (noDuplicates && this.contains(obj)) // check
        return -1;
        
    if (index < 0 || index > this._lastIndex) // check not over array bounds
        return -1;
        
    // move everything up
    for (var i = this._lastIndex; i >= index; i--)
        this[i+1] = this[i];
        
    // Move passed object into slot.
    this[index] = obj;
    
    // Add our lastIndex.
    this._lastIndex++;   
    
    var args = new ajax.collections.ArrayListEventArgs(null, this, obj, index);
    this.onAdded.call(this, args);
    return index;                         
}
ajax.collections.ArrayList.prototype.insert = ajax.collections.ArrayList.prototype.addAt;

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.remove = function(obj, lowestInstanceOnly)
{///<returns type="number" integer="true">Returns the index of the last removed item.</returns>
 ///<param name="obj" type="Object">The object to remove</param>
 ///<param name="lowestInstanceOnly" type="bool">Optional. Pass true to only remove the lowest instance, otherwise all instances will be removed.</param>
    var index = this.indexOf(obj);
    var lastRemoved = -1;
    while(index >= 0) // in case of duplicates.
    {        
        for (var i = index; i < this._lastIndex; i++)        
            this[i] = this[i+1];
        this[this._lastIndex--] = null;        
        
        var args = new ajax.collections.ArrayListEventArgs(null, this, obj, index); 
        this.onRemoved.call(this, args);
        lastRemoved = index;
        index = lowestInstanceOnly ? -1 : this.indexOf(obj);
    }    
    return lastRemoved;
}

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.removeAt = function(index)
{///<returns type="number" integer="true">Returns the index position of the removed item.</returns>
 ///<param name="index" integer="true">The position index to remove.</param>
    if (index < 0 || index > this._lastIndex) // check
        return -1;
    
    var obj = this[index]; // store obj to remove
            
    for (var i = index; i < this._lastIndex; i++)
        this[i] = this[i+1];
        
    this[this._lastIndex--] = null;
    
    var args = new ajax.collections.ArrayListEventArgs(null, this, obj, index);
    this.onRemoved.call(this, args); 
    return index;                 
}

//-----------------------------------------------------------------------------
ajax.collections.ArrayList.prototype.clear = function()
{///<summary>Clears all elements from the array</summary>
    
    var args = new ajax.collections.ArrayListEventArgs(null, this, null, 0);    
    while (this._lastIndex > -1)
    {
        args.obj = this[this._lastIndex];
        args.index = this._lastIndex;
        this[this._lastIndex--] = null;
        this.onRemoved.call(this, args);        
    }    
}


// Statics
//-----------------------------------------------------------------------------
ajax.collections.ArrayList.cast = function(obj)
{///<returns type="ajax.collections.ArrayList"/>
    return obj;
}